import { AppStore } from '..'
import { ComponentFactory } from '../mapper'
import { ViewGroup, ViewComponent } from '../mapper/components'
import { JSONParserMiddleware, TabBarParserMiddleware, PageParserMiddleware } from '../middleware/'

export interface TabItem {
  /** 唯一标识 */
  id: string
  /** 标题 */
  title: string
  /** 图标 */
  icon?: string | undefined
  /** 对应的page的id */
  pageId?: string
  /** 页面元素 */
  component: React.ReactNode | undefined
}

// 中间件接口定义
export interface Middleware {
  process(context: Context, next: () => Promise<void>): Promise<void>
}

// 上下文
export class Context {
  /** 低代码结构数据 */
  json: any
  /** tabbar的数据，也是UI层的结构树 */
  tabInfo: TabItem[]
  /** UI层传过来的数据，就是app的store */
  store: AppStore
}

// 中间件链构建器
class MiddlewarePipeline {
  private middlewares: Middleware[] = []
  use(middleware: Middleware): MiddlewarePipeline {
    this.middlewares.push(middleware)
    return this
  }

  // 执行队列中的中间件，直到最后一个中间件或者遇到中断
  async process(context: Context): Promise<void> {
    let index = -1

    const runner = async (i: number): Promise<void> => {
      if (i <= index) {
        throw new Error('next() 被调用了多次')
      }
      index = i
      const middleware = this.middlewares[i]
      if (middleware) {
        await middleware.process(context, () => runner(i + 1))
      }
    }

    await runner(0)
  }
}

// SDK入口
export class FlexCode {
  private pipeline: MiddlewarePipeline
  private store: AppStore

  constructor(action: AppStore) {
    this.store = action
    this.pipeline = new MiddlewarePipeline()
    // 1、解析json
    this.pipeline.use(new JSONParserMiddleware())
    // 2、解析tabBar
    this.pipeline.use(new TabBarParserMiddleware())
    // 3、解析页面
    this.pipeline.use(new PageParserMiddleware())
  }

  async parse(json: any): Promise<TabItem[]> {
    const context = new Context()
    context.json = json
    context.store = this.store
    await this.pipeline.process(context)
    return context.tabInfo
  }
  // 测试用，正式发包应删除
  async test(json: any): Promise<Context> {
    const context = new Context()
    context.json = json
    await this.pipeline.process(context)
    return context
  }
}
